package com.javasm.sys.task;

import com.javasm.sys.SysTimingTask;
import com.javasm.sys.TasksService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.scheduling.config.ScheduledTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.stereotype.Component;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;


@Component
public class CrmTimingTask implements SchedulingConfigurer {

    @Autowired
    private TasksService tasksService;

    private ScheduledTaskRegistrar scheduledTaskRegistrar;

    private Map<String,ScheduledTask> scheduledTaskMap = new ConcurrentHashMap<>();

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {

        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
        scheduledTaskRegistrar.setTaskScheduler(new ConcurrentTaskScheduler(scheduledExecutorService));
        this.scheduledTaskRegistrar=scheduledTaskRegistrar;
        List<SysTimingTask> list = tasksService.getRunningTasks();
        for (SysTimingTask t : list) {
            String id = t.getId();
            String taskClz = t.getTaskMethod();
            String taskCron = t.getTaskCorn();
            int index = taskClz.lastIndexOf(".");
            String clzStr = taskClz.substring(0, index);
            String methodStr = taskClz.substring(index + 1, taskClz.length());
            Runnable runnable = null;
            try {
                Class aClass = Class.forName(clzStr);
                Constructor constructor = aClass.getConstructor();
                Object o = constructor.newInstance();
                Method method = aClass.getMethod(methodStr);
                runnable = createRunnable(o,method);
            } catch (Exception e) {
                runnable = null;
            }
            if(runnable != null) {
                CronTask cronTask = new CronTask(runnable, taskCron);
                ScheduledTask scheduledTask = scheduledTaskRegistrar.scheduleCronTask(cronTask);
                scheduledTaskMap.put(id,scheduledTask);
            }
        }
    }

    public boolean cancelTask(String taskid) {
        ScheduledTask scheduledTask = scheduledTaskMap.get(taskid);
        if(scheduledTask != null) {
            scheduledTask.cancel();
            scheduledTaskMap.remove(taskid);
            return true;
        }

        return false;
    }

    public boolean registrarTask(SysTimingTask t) {

        String id = t.getId();
        String taskClz = t.getTaskMethod();
        String taskCron = t.getTaskCorn();

        int index = taskClz.lastIndexOf(".");
        String clzStr = taskClz.substring(0, index);
        String methodStr = taskClz.substring(index + 1, taskClz.length());
        Runnable runnable = null;
        try {
            Class aClass = Class.forName(clzStr);
            Constructor constructor = aClass.getConstructor();
            Object o = constructor.newInstance();
            Method method = aClass.getMethod(methodStr);
            runnable = createRunnable(o,method);
        } catch (Exception e) {
            runnable = null;
        }

        if(runnable != null) {
            CronTask cronTask = new CronTask(runnable, taskCron);
            ScheduledTask scheduledTask = scheduledTaskRegistrar.scheduleCronTask(cronTask);
            scheduledTaskMap.put(id,scheduledTask);
            return true;
        }
        return false;
    }

    public  Runnable createRunnable(Object o, Method method)throws Exception {

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    method.invoke(o);
                } catch (Exception e) {
                   e.printStackTrace();
                }
            }
        };

        return runnable;
    }


}
